#include "StringUtil.h"
#include <boost/tokenizer.hpp>

namespace egg {

    void StringUtil::trim(string& str, bool left, bool right) {
        static const string delims = " \t\r\n";
        if (right)
            str.erase(str.find_last_not_of(delims) + 1); // trim right
        if (left)
            str.erase(0, str.find_first_not_of(delims)); // trim left
    }

    //-----------------------------------------------------------------------

    StringVector StringUtil::split(const string& str, const string& delims, unsigned int maxSplits) {
        StringVector ret;
        // Pre-allocate some space for performance
        ret.reserve(maxSplits ? maxSplits + 1 : 10); // 10 is guessed capacity for most case

        unsigned int numSplits = 0;

        // Use STL methods 
        size_t start, pos;
        start = 0;
        do {
            pos = str.find_first_of(delims, start);
            if (pos == start) {
                // Do nothing
                start = pos + 1;
            } else if (pos == string::npos || (maxSplits && numSplits == maxSplits)) {
                // Copy the rest of the string
                ret.push_back(str.substr(start));
                break;
            } else {
                // Copy up to delimiter
                ret.push_back(str.substr(start, pos - start));
                start = pos + 1;
            }
            // parse up to next real data
            start = str.find_first_not_of(delims, start);
            ++numSplits;

        } while (pos != string::npos);

        return ret;
    }
    
    StringVector StringUtil::tokenise(const string& str, const string& delims) {
		using namespace boost;
		typedef tokenizer<char_separator<char>> StringToke;
		char_separator<char> sep(delims.c_str());
		StringToke tok(str,sep);
		StringVector ret;  
		for(StringToke::iterator beg=tok.begin(); beg!=tok.end();++beg)
			ret.push_back(*beg);  
		return ret;
    }

    StringVector StringUtil::tokenise(const string& str, const string& dropDelims,const string& keepDelims){
        using namespace boost;
        typedef tokenizer<char_separator<char>> StringToke;
        char_separator<char> sep(dropDelims.c_str(),keepDelims.c_str());
        StringToke tok(str,sep);
        StringVector ret;  
        for(StringToke::iterator beg=tok.begin(); beg!=tok.end();++beg)
            ret.push_back(*beg);  
        return ret;
    }

    //-----------------------------------------------------------------------

    bool StringUtil::startWith(const string& str, const string& pattern) {
        size_t length=pattern.length();
        for(int i=0;i<length;i++){
            if(str[i]!=pattern[i])
                return false;
        }
        return true;
    }
    //-----------------------------------------------------------------------

    bool StringUtil::endsWith(const string& str, const string& pattern) {
        size_t thisLen = str.length();
        size_t patternLen = pattern.length();
        if (thisLen < patternLen || patternLen == 0)
            return false;
        string endOfThis = str.substr(thisLen - patternLen, patternLen);
        return (endOfThis == pattern);
    }

    void StringUtil::splitFileName(const string& fullName,string& baseName, string& extension) {
        size_t i = fullName.find_last_of(".");
        if (i == string::npos) {
            extension.clear();
            baseName = fullName;
        } else {
            extension = fullName.substr(i + 1);
            baseName = fullName.substr(0, i);
        }
    }

    //-----------------------------------------------------------------------

    bool StringUtil::match(const string& str, const string& pattern) {
        string tmpStr = str;
        string tmpPattern = pattern;

        string::const_iterator strIt = tmpStr.begin();
        string::const_iterator patIt = tmpPattern.begin();
        string::const_iterator lastWildCardIt = tmpPattern.end();
        while (strIt != tmpStr.end() && patIt != tmpPattern.end()) {
            if (*patIt == '*') {
                lastWildCardIt = patIt;
                // Skip over looking for next character
                ++patIt;
                if (patIt == tmpPattern.end()) {
                    // Skip right to the end since * matches the entire rest of the string
                    strIt = tmpStr.end();
                } else {
                    // scan until we find next pattern character
                    while (strIt != tmpStr.end() && *strIt != *patIt)
                        ++strIt;
                }
            } else {
                if (*patIt != *strIt) {
                    if (lastWildCardIt != tmpPattern.end()) {
                        // The last wildcard can match this incorrect sequence
                        // rewind pattern to wildcard and keep searching
                        patIt = lastWildCardIt;
                        lastWildCardIt = tmpPattern.end();
                    } else {
                        // no wildwards left
                        return false;
                    }
                } else {
                    ++patIt;
                    ++strIt;
                }
            }

        }
        // If we reached the end of both the pattern and the string, we succeeded
        if (patIt == tmpPattern.end() && strIt == tmpStr.end()) {
            return true;
        } else {
            return false;
        }

    }


	bool StringUtil::match(string& str,StringVector& strs){
		for(int i=0;i<strs.size();i++){
			if(str==strs[i])
				return true;
		}
		return false;
	}
    //-----------------------------------------------------------------------

    const string StringUtil::replaceAll(const string& source, const string& replaceWhat, const string& replaceWithWhat) {
        string result = source;
        string::size_type pos = 0;
        while (1) {
            pos = result.find(replaceWhat, pos);
            if (pos == string::npos) break;
            result.replace(pos, replaceWhat.size(), replaceWithWhat);
            pos += replaceWithWhat.size();
        }
        return result;
    }

}
